#include "StdAfx.h"
#include "mpegts.h"
#include "TreeNode.h"

CTreeNode* g_hRoot = NULL;
CTreeCtrl* g_hTreeCtrl = NULL;

static BOOL FreeTree(CTreeNode* pTreeRoot);

BOOL TreeInitial(CTreeCtrl* pTree)
{
	BOOL bRet = FALSE;

	if(pTree)
	{
		g_hTreeCtrl = pTree;
		bRet = TRUE;
	}

	return bRet;
}

BOOL TreeTerm(void)
{
	BOOL bRet = FALSE;

	if(g_hRoot)
	{
		//free all Tree nodes...		
		bRet = FreeTree(g_hRoot);
	}
	return bRet;
}

BOOL AddTreeNode(CTreeNode* pNode, CTreeNode* pParent, CTreeNode* pInsertAfter)
{
	BOOL bRet = FALSE;
	BOOL bEnsureVisible = FALSE;

	if(pNode)
	{
		DWORD parameter = pNode->GetItemData();
		USHORT pid = (parameter&0xFFFF0000)>>16;
		BYTE table_id = BYTE(parameter&0xFF);
		DWORD parameterEx = pNode->GetItemDataEx();
		USHORT value = (parameterEx&0xFFFF0000)>>16;
		BYTE version = (parameterEx&0xFF00)>>8;
		BYTE section_number = parameterEx&0xFF;

		if(pNode->GetItemData() == 0)
		{
			if(pNode->GetItemType() == PSI)
			{
				pNode->SetItemText(_T("PSI"));
			}
			else if(pNode->GetItemType() == SI)
			{
				pNode->SetItemText(_T("SI"));
			}
			else
			{
				//Root, show the ts name
				VERIFY(g_hRoot == pNode);
			}
		}
		else if(pNode->GetItemDataEx() == 0) // add the table node
		{
			if(pParent == NULL)
			{
				if(table_id == TABLE_PAT || table_id == TABLE_CAT || table_id == TABLE_PMT)
				{
					CTreeNode* pPSINode = new CTreeNode();
					pPSINode->SetItemType(PSI);
					AddTreeNode(pPSINode, g_hRoot, NULL);
					pParent = pPSINode;
				}
				else
				{
					CTreeNode* pSINode = new CTreeNode();
					pSINode->SetItemType(SI);
					AddTreeNode(pSINode, g_hRoot, GetTreeNode(PSI, 0, 0));
					pParent = pSINode;
				}
				
			}

			CString ItemText;
			switch(table_id)
			{
			case TABLE_PAT:
				ItemText = _T("PAT");
				break;
			case TABLE_PMT:
				ItemText = _T("PMT");
				break;
			case TABLE_CAT:
				ItemText = _T("CAT");
				break;
			case TABLE_NIT_ACTUAL:
				ItemText = _T("NIT Actual");
				break;
			case TABLE_SDT_ACTUAL:
				ItemText = _T("SDT Actual");
				break;
			case TABLE_SDT_OTHER:
				ItemText = _T("SDT Other");
				break;
			case TABLE_BAT:
				ItemText = _T("BAT");
				break;
			case TABLE_EIT_PF_ACTUAL:
				ItemText = _T("EIT PF Actual");
				break;
			case TABLE_EIT_PF_OTHER:
				ItemText = _T("EIT PF Other");
				break;
			case TABLE_TDT:
				ItemText = _T("TDT");
				break;
			case TABLE_TOT:
				ItemText = _T("TOT");
				break;
			default:
				if(table_id >= 0x50 && table_id <= 0x5F)
				{
					ItemText = _T("EIT Schedule Actual");
				}
				else if(table_id >= 0x60 && table_id <= 0x6F)
				{
					ItemText = _T("EIT Schedule Other");
				}
				else
				{
					ItemText = _T("Unknown Table");
				}
				break;
			}
			pNode->SetItemText(ItemText);
			bEnsureVisible = TRUE;
		}
		else
		{
			CString ItemText;
			ItemText.Format(_T("Section:[0x%04X(%d)](%d) - version:%d"),value, value, section_number, version);
			pNode->SetItemText(ItemText);
			if (pParent)
			{
				USHORT nChildCount = pParent->ChildCounter();
				HTREEITEM hItem = (HTREEITEM)pParent->GetItemHandle();
				CString text;
				CString text_org = pParent->GetItemText();
				if(hItem)
				{
					if(nChildCount > 1)
					{
						text.Format(_T(" - (%d items)"),nChildCount);						
					}
					else
					{					
						text = _T(" - (1 item)");
					}
					text = text_org + text;
					g_hTreeCtrl->SetItemText(hItem, text);
				}
			}
		}

		TVINSERTSTRUCT tvInsert;
		HTREEITEM hItem = NULL;
		tvInsert.item.mask = TVIF_TEXT;
		tvInsert.item.pszText = (LPWSTR)pNode->GetItemText();
		tvInsert.hParent = NULL;
		tvInsert.hInsertAfter = NULL;

		if(pParent == NULL)
		{
			if (g_hRoot == NULL)
			{
				g_hRoot = pNode;
				tvInsert.hInsertAfter = NULL;
			}
			tvInsert.hParent = NULL;		
		}
		else
		{
			tvInsert.hParent = (HTREEITEM)pParent->GetItemHandle();
		}
		
		if (pInsertAfter == NULL)
		{
			tvInsert.hInsertAfter = TVI_FIRST;
		}
		else
		{
			tvInsert.hInsertAfter = (HTREEITEM)pInsertAfter->GetItemHandle();
		}

		hItem = g_hTreeCtrl->InsertItem(&tvInsert);
		if(hItem)
		{
			pNode->SetItemHandle(hItem);
			g_hTreeCtrl->SetItemData(hItem, (DWORD_PTR)pNode);
			if(bEnsureVisible)
			{
				g_hTreeCtrl->EnsureVisible(hItem);
			}
			if(pParent)
			{
				if(pParent->GetChild() && pInsertAfter == NULL)
				{
					CTreeNode* pChild = pParent->GetChild();
					pParent->AddChild(pNode);
					pNode->AddBrother(pChild);
				}
				else if(pParent->GetChild() && pInsertAfter != NULL)
				{
					CTreeNode* pNextNode = pInsertAfter->GetNextBrother();

					pInsertAfter->AddBrother(pNode);
					pNode->AddBrother(pNextNode);
				}
				else
				{
					pParent->AddChild(pNode);
				}
			}
		}

		bRet = TRUE;
	}

	return bRet;
}

CTreeNode* GetRootNode(void)
{
	return g_hRoot;
}

CTreeNode* GetTreeNode(BYTE type, DWORD parameter, DWORD parameterEx)
{
	CTreeNode* pNode = NULL;

	if(parameter == 0)
	{
		if(type != 0 && g_hRoot)
		{
			CTreeNode *pA = g_hRoot->GetChild();
			while(pA)
			{
				if(pA->GetItemType() == type)
				{
					pNode = pA;
					break;
				}
				pA = pA->GetNextBrother();
			}
		}
	}
	else if(parameterEx == 0)
	{
		if(GetTreeNode(type, 0, 0))
		{
			CTreeNode* pA = (GetTreeNode(type, 0, 0))->GetChild();
			while(pA)
			{
				if(pA->GetItemData() == parameter)
				{
					pNode = pA;
					break;
				}
				pA = pA->GetNextBrother();
			}
		}
	}
	else
	{
		CTreeNode* pA = (GetTreeNode(type, parameter, 0))->GetChild();
		while(pA)
		{
			if(pA->GetItemDataEx() == parameterEx)
			{
				pNode = pA;
				break;
			}
			pA = pA->GetNextBrother();
		}
	}

	return pNode;
}

CTreeNode* GetParentNode(CTreeNode* pNode)
{
	CTreeNode* pParent = NULL;
	if(pNode)
	{
		if(pNode->GetItemData() == 0)
		{
			if(pNode->GetItemType() != 0)
			{
				pParent = g_hRoot;
			}
			else
			{
				pParent = NULL;
				g_hRoot = pNode;
			}
		}
		else if(pNode->GetItemDataEx() == 0)
		{
			pParent = GetTreeNode(pNode->GetItemType(), 0, 0);
		}
		else
		{
			pParent = GetTreeNode(pNode->GetItemType(), pNode->GetItemData(), 0);
		}
	}

	return pParent;
}

CTreeNode* GetInsertAfter(CTreeNode* pNode)
{
	CTreeNode* pInsertAfter = NULL;

	if(pNode)
	{
		if(pNode->GetItemData() == 0)
		{
			if(pNode->GetItemType() == PSI)
			{
				pInsertAfter = NULL;
			}
			else if(pNode->GetItemType() == SI)
			{
				pInsertAfter = GetTreeNode(PSI, 0, 0);
			}
			else
			{
				//root node
				pInsertAfter = NULL;
			}
		}
		else if(pNode->GetItemDataEx() == 0)
		{
			DWORD parameter = pNode->GetItemData();
			USHORT pid = (parameter&0xFF00)>>16;
			BYTE table_id = BYTE(parameter&0xFF);
			CTreeNode* pA = GetTreeNode(pNode->GetItemType(), 0, 0);
			if(pA)
			{
				pA = pA->GetChild();
				while(pA)
				{
					BYTE pA_table_id = pA->GetItemData()&0xFF;
					if(table_id < pA_table_id)
					{
						break;
					}
					pInsertAfter = pA;
					pA = pA->GetNextBrother();
				}
			}
			
		}
		else
		{
			DWORD parameter = pNode->GetItemData();
			USHORT pid = (parameter&0xFFFF0000)>>16;
			BYTE table_id = BYTE(parameter&0xFF);
			DWORD parameterEx = pNode->GetItemDataEx();
			USHORT value = (parameterEx&0xFFFF0000)>>16;
			BYTE version = (parameterEx&0xFF00)>>8;
			BYTE section_number = parameterEx&0xFF;
			CTreeNode* pA = GetTreeNode(pNode->GetItemType(), parameter, 0);
			if(pA)
			{
				pA = pA->GetChild();
				while(pA)
				{
					USHORT pA_value = (pA->GetItemDataEx()&0xFFFF0000)>>16;
					BYTE pA_version = (pA->GetItemDataEx()&0xFF00)>>8;
					BYTE pA_section_number = pA->GetItemDataEx()&0xFF;
					if((value==pA_value&&section_number < pA_section_number) || value < pA_value)
					{
						break;
					}
					pInsertAfter = pA;
					pA = pA->GetNextBrother();
				}
			}			
		}
	}
	return pInsertAfter;
}

static BOOL FreeTree(CTreeNode* pTreeRoot)
{
	BOOL bRet = FALSE;

	if(pTreeRoot)
	{
		if(pTreeRoot->GetChild())
		{
			FreeTree(pTreeRoot->GetChild());
		}

		if(pTreeRoot->GetNextBrother())
		{
			FreeTree(pTreeRoot->GetNextBrother());
		}
		
		delete pTreeRoot;

		bRet = TRUE;
	}

	return bRet;
}


////////////////////////////////////CTreeNode class///////////////////////////////////////////////////////////

CTreeNode::CTreeNode(void)
{
	m_parameter = 0;
	m_parameterEx = 0;
	m_type = 0;
	m_nCount = 0;
	m_pChild = NULL;
	m_pBrother = NULL;
	m_handle = NULL;
	m_szText = NULL;
	m_szText = new TCHAR[MAX_TEXT_SIZE];
}

CTreeNode::CTreeNode(LPCTSTR lpszText)
{
	m_szText = NULL;
	m_szText = new TCHAR[MAX_TEXT_SIZE];
	wcsncpy_s(m_szText, MAX_TEXT_SIZE-1, lpszText, wcslen(lpszText));
	m_parameter = 0;
	m_parameterEx = 0;
	m_type = 0;
	m_nCount = 0;
	m_pChild = NULL;
	m_pBrother = NULL;
	m_handle = NULL;
}

CTreeNode::CTreeNode(DWORD parameter, DWORD parameterEx)
{
	m_parameter = parameter;
	m_parameterEx = parameterEx;
	m_nCount = 0;
	m_type = 0;
	m_pChild = NULL;
	m_pBrother = NULL;
	m_handle = NULL;
	m_szText = NULL;
	m_szText = new TCHAR[MAX_TEXT_SIZE];
}

CTreeNode::~CTreeNode(void)
{
	if (m_szText)
	{
		delete[] m_szText;
		m_szText = NULL;
	}
}

CTreeNode* CTreeNode::GetChild(void)
{
	return m_pChild;
}

CTreeNode* CTreeNode::GetNextBrother(void)
{
	return m_pBrother;
}

BOOL CTreeNode::AddChild(CTreeNode* pNode)
{
	m_pChild = pNode;
	return TRUE;
}

BOOL CTreeNode::AddBrother(CTreeNode* pNode)
{
	m_pBrother = pNode;
	return TRUE;
}

BOOL CTreeNode::SetItemText(LPCTSTR lpszText)
{
	BOOL bRet = FALSE;
	wcsncpy_s(m_szText, MAX_TEXT_SIZE-1, lpszText, wcslen(lpszText));
	return TRUE;
}

LPCTSTR CTreeNode::GetItemText(void)
{
	return m_szText;
}

BOOL CTreeNode::SetItemType(BYTE type)
{
	m_type = type;
	return TRUE;
}

BYTE CTreeNode::GetItemType(void)
{
	return m_type;
}

BOOL CTreeNode::SetItemData(DWORD parameter)
{
	m_parameter = parameter;
	return TRUE;
}

DWORD CTreeNode::GetItemData(void)
{
	return m_parameter;
}

BOOL CTreeNode::SetItemDataEx(DWORD parameterEx)
{
	m_parameterEx = parameterEx;
	return TRUE;
}

DWORD CTreeNode::GetItemDataEx(void)
{
	return m_parameterEx;
}

BOOL CTreeNode::SetItemHandle(void* handle)
{
	m_handle = handle;
	return TRUE;
}

void* CTreeNode::GetItemHandle(void)
{
	return m_handle;
}

USHORT CTreeNode::ChildCounter(void)
{
	m_nCount++;
	return m_nCount;
}

BOOL CTreeNode::operator == (const CTreeNode& Node)const
{
	return TRUE;
}